/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package pop3proxy.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import pop3proxy.logging.Logger;
import pop3proxy.persistence.Account;
import pop3proxy.persistence.Mailbox;

/**
 * Dieser Thread holt alle noch nicht runtergeladenen Threads eines Accounts 
 * und speichert diese in der Mailbox.
 */
class MailThread extends Thread {
    private Account account;
    private Mailbox mailbox;
    private BufferedReader receiver;
    private OutputStreamWriter sender;
    
    MailThread(Account acc, Mailbox mailbox) {
        account = acc;
        this.mailbox = mailbox;
    }

    @Override
    public void run() {
        try (Socket clientSocket = new Socket(account.hostname, account.port)) {
            fetchMails(clientSocket);
        } catch (UnknownHostException ex) {
            System.err.println("Host: " + account.hostname + " konnte nicht aufgelöst werden, deaktiviere account.");
            account.active = false;
        } catch (IOException ex) {
            System.err.println("Verbindungsproblem");
            System.err.println(ex);
        }
    }

    private void fetchMails(Socket clientSocket) throws IOException {        
        receiver = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));;
        sender = new OutputStreamWriter(clientSocket.getOutputStream());
        
        if (!recv().startsWith("+OK")) {
            System.err.println("Host " + account.hostname + " hat eine ungültige Begrüßung gesendet");
            return;
        }
        
        //LOGIN
        send("USER " + account.username + "\r\n");
        if (!recv().startsWith("+OK")) {
            System.err.println("Username " + account.username + " ist dem Host " + account.hostname + " unbekannt");
            account.active = false;
            send("QUIT\r\n");
            return;
        }
        send("PASS " + account.password + "\r\n");
        if (!recv().startsWith("+OK")) {
            System.err.println("Username/Passwort für account " + account.username + " auf " + account.hostname + " ungültig");
            account.active = false;
            send("QUIT\r\n");
            return;
        }
        
        //TRANSACTION-STATE
        send("STAT\r\n");
        String[] stat = recv().split("\r")[0].split(" ");
        if (!stat[0].equals("+OK")) {
            System.err.println("Unerwartetes -ERR auf STAT");
            send("QUIT\r\n");
            return;
        }
        int unreadMails = Integer.parseInt(stat[1]);
        if (unreadMails == 0) {
            send("QUIT\r\n");
            return;
        }
        //We have unread Mails
        send("UIDL\r\n");
        if (!recv().startsWith("+OK")) {
            System.err.println("UIDL Befehl ist dem Server unbekannt");
            send("QUIT\r\n");
            return;
        }
        
        Map<String,String> uidlMap = parseUidls(readLines());
        
        for(Entry<String,String> entry : uidlMap.entrySet()) { //Download all mails, we don't have
            String uidl = entry.getValue();
            String nr = entry.getKey();
            List<String> mail = downloadMail(nr);
            if (Client.deleteMails) {
                send("DELE " + nr + "\r\n");
                recv(); //ignore response
            }
            mailbox.writeMail(uidl, mail);
        }
        //DONE! :D
        send("QUIT\r\n");
    }
    
    private String recv() throws IOException {
        String msg = receiver.readLine();
        Logger.file.log("<C<\t" + msg);
        return msg;
    }
    
    private List<String> readLines() throws IOException {
        List<String> lines = new ArrayList<>();
        for(String line = recv(); !line.equals("."); line = recv()) {
            if (line.startsWith("."))
              line = line.substring(1);
            lines.add(line);
        }
        return lines;
    }

    private Map<String, String> parseUidls(List<String> lines) {
        Map<String,String> uidlMap = new HashMap<>();
        for (String line : lines) {
            String[] parts = line.split(" ");
            String nr = parts[0];
            String uidl = parts[1];
            if (!mailbox.containsMail(uidl))
                uidlMap.put(nr, uidl);
        }
        return uidlMap;
    }

    private List<String> downloadMail(String nr) throws IOException {
        send("RETR " + nr + "\r\n");
        if (!recv().startsWith("+OK")) {
            send("QUIT\r\n");
            throw new IOException("-ERR als antwort auf RETR " + nr + " erhalten!");
        }
        
        return readLines();
    }

    private void send(String string) throws IOException {
        sender.write(string);
        Logger.file.log(">C>\t" + string);
        sender.flush();
    }
}
